package cate.game.role.login.msg;

import cate.game.GameBody;
import cate.game.client.ClientContext;
import cate.game.client.msg.ClientMsg;
import cate.game.client.msg.MsgConfig;
import cate.game.client.msg.MsgInput;
import cate.game.client.msg.id.MsgIdBLogin;
import cate.game.event.master.RoleLoginEvent;
import cate.game.log.GameLoggerFactory;
import cate.game.role.Role;
import cp.solution.business.sys.account.dto.AccountLoginData;
import easy.java.dev.note.NoteField;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;

import java.util.TimeZone;
import java.util.concurrent.locks.ReentrantLock;

@Slf4j
@ToString
@ClientMsg(title = "登录开始 の 请求")
public class LoginStartReq implements MsgInput {

    @NoteField("登录token")
    public String token;
    @NoteField("角色ID")
    public String roleId;
    @NoteField("邀请码")
    public String inviteCode;

    @Override
    public MsgConfig conf() {
        return MsgIdBLogin.START_REQ;
    }

    private static AccountLoginData getLoginData(GameBody game, String token) {
        try {
            return game.apis().login.account.getLoginData(token);
        } catch (Exception e) {
            // token invalid 的时候 就会抛异常，属于正常业务逻辑
            log.error("token={} {} (通常是token超时引起的，重新登录就好了)", token, e.getMessage());
            return null;
        }
    }

    @Override
    public void execute(GameBody game, ClientContext cc) {
        log.info("登录开始 の 请求 执行参数 {}", this);
        if(!game.isRunning()) {
            log.warn("该游戏服已关闭，拒绝处理业务");
            return;
        }
        if(game.clientIgn) {
            log.warn("该游戏服clientIgn，拒绝处理业务");
            return;
        }
        AccountLoginData ld = getLoginData(game, this.token);
        LoginStartResp resp = new LoginStartResp();
        if(ld == null) {
            log.warn("请求登录失败 {}， 因为根据token找不到登录数据, 可能该token已经失效", this);
            resp.code = LoginStartResp.CODE_LOGIN_TOKEN_INVALID;
            resp.message = "login token invalid";
            cc.sendNow(resp);
            return;
        }

        game.stat.whenAccountLogin(ld.getAccount());
        cc.setLoginData(ld);

        if(StringUtils.isBlank(this.roleId)) {
            if(!game.config.allowCreateRole()) {
                resp.code = LoginStartResp.CODE_NOT_ALLOW_CREATE_ROLE;
                resp.message = "not allow create role";
                cc.sendNow(resp);
                return;
            }
            // 新创角
            resp.code = LoginStartResp.CODE_PLEASE_CREATE_ROLE;
            resp.message = "please create role";
        } else {
            log.info("玩家登录数据：{}", ld.getAccount());
            //这里有可能并发的
            boolean hasKicked = false;
            Role role = game.role.findOnline(this.roleId);
            if(role != null && role.getCc() != null){
                boolean normalAction = role.log.isNormalAction("login-req", 5000);
                if(!normalAction){
                    resp.code = LoginStartResp.CODE_LOGIN_TOKEN_INVALID;
                    resp.message = "login token invalid";
                    cc.sendNow(resp);
                    return;
                }
                hasKicked = true;
                // 顶号情形
                log.warn("被顶号: {} {}", role.getUid(), role.getBase().name);
                game.notice.message(role, "你被顶号了");
                role.sendNow(new LoginDisplaceResp());

                role.getCc().kickOff(game);
            }else{
                role = game.role.getRole(this.roleId);
            }
            // 客户端觉得 有角色
            if(role == null) {
                resp.code = LoginStartResp.CODE_CANNOT_FIND_ROLE;
                resp.message = "cannot find role";
            } else {
                //并发进入这里
                final ReentrantLock lock = game.role.getLock(roleId);
                lock.lock();
                try{
                    Role onlineRole = null;
                    if(!hasKicked && (onlineRole = game.role.findOnline(this.roleId)) != null && onlineRole.getCc() != null){
                        onlineRole.getCc().kickOff(game);
                    }
                    role = onlineRole == null ? role : onlineRole;

                    // 为了支持 导入内网环境的 外网账号
//                    role.getBase().accountId = ld.getAccount().getId();
                    // 为了支持 导入内网环境的 外网账号

                    if(role.getBase().accountId != ld.getAccount().getId()) {
                        resp.code = LoginStartResp.CODE_ACCOUNT_MISMATCH_ROLE;
                        resp.message = "account mismatch role";
                    } else {
                        //角色已加载，并且绑定网络通讯上下文
                        role.initAllPart();
                        cc.bindRole(role, game);
                        role.getBase().read(ld);
                        role.getBase().invite.setLoginCode(this.inviteCode);
                        if(role.getBase().login.isBanned()) {
                            resp.code = LoginStartResp.CODE_ROLE_BAN_LOGIN;
                            resp.message = role.getBase().login.getBanReason();
                        } else {
                            resp.code = LoginStartResp.CODE_ROLE_HAS_BEEN_LOADED;
                            resp.message = "role has been loaded";
                            game.eventDispatcher.dispatchEvent(new RoleLoginEvent(role));
                        }
                    }
                    game.stat.whenLogin(role);
                }finally {
                    lock.unlock();
                }
            }
        }


        resp.openTime = game.status.getOpenTime();
        resp.timestamp = System.currentTimeMillis();
        resp.timeZoneStr = getTimeZoneStr();
        resp.isMiniSH = game.config.isMiniSH();
        cc.sendNow(resp);
    }


    private static String getTimeZoneStr(){
        int rawOffset = TimeZone.getDefault().getRawOffset();
        String symbol = "+";
        if (rawOffset < 0)
        {
            symbol = "-";
        }
        rawOffset = Math.abs(rawOffset);
        int offsetHore = rawOffset / 3600000;
        return symbol + offsetHore;
    }
}
